﻿using System;
using System.Linq;
using Belphegor.Composites;
using Belphegor.Dynamics;
using Belphegor.Helpers;
using Zeta;
using Zeta.Common.Helpers;
using Zeta.CommonBot;
using Zeta.Internals.Actors;
using Zeta.TreeSharp;
using Action = Zeta.TreeSharp.Action;


/*
 *  Credits to Nuok whom are the author of this routine.
 */

namespace Belphegor.Routines
{
    public class Monk
    {
        [Class(ActorClass.Monk)]
        [Behavior(BehaviorType.Buff)]
        public static Composite MonkBuff()
        {
            return
            new PrioritySelector(
                new SelfCast(SNOPower.Monk_BreathOfHeaven,
                    extra => !ZetaDia.Me.HasBuff(SNOPower.Monk_BreathOfHeaven)),
                new SelfCast(SNOPower.Monk_MantraOfHealing, extra => !ZetaDia.Me.HasBuff(SNOPower.Monk_MantraOfHealing)),
                Spell.Buff(SNOPower.Monk_MysticAlly, extra => !HasMysticAlly)
            );
        }

        [Class(ActorClass.Monk)]
        [Behavior(BehaviorType.Combat)]
        public static Composite MonkCombat()
        {
            return
                new PrioritySelector(ctx => CombatTargeting.Instance.FirstNpc,

                    new SelfCast(SNOPower.Monk_Serenity,
                            extra => ZetaDia.Me.HitpointsCurrentPct <= 0.6 ||
                                     (ZetaDia.Me.IsFeared || ZetaDia.Me.IsStunned || ZetaDia.Me.IsFrozen || ZetaDia.Me.IsBlind || ZetaDia.Me.IsRooted)),

                    Common.CreateWaitWhileIncapacitated(),
                    Common.CreateWaitForAttack(),
                    Common.CreateUsePotion(),

                    new SelfCast(SNOPower.Monk_BreathOfHeaven,
                            extra => ZetaDia.Me.HitpointsCurrentPct <= 0.7),
                    new SelfCast(SNOPower.Monk_InnerSanctuary, extra => ZetaDia.Me.HitpointsCurrentPct <= 0.4),

                        new Decorator(ctx => ctx != null,
                            new PrioritySelector(

                                new CastOnUnit(SNOPower.Monk_DashingStrike,
                                    ctx => ((DiaUnit)ctx).ACDGuid,
                                    extra => CombatTargeting.Instance.FirstNpc.Distance > 20f),

                                new Decorator(ctx => ctx != null && ((DiaUnit)ctx).Distance > 20f,
                                        CommonBehaviors.MoveTo(ctx => ((DiaUnit)ctx).Position, "Moving towards unit")),

                                //Spells to move closer 
                                new CastOnUnit(SNOPower.Monk_FistsofThunder,
                                    ctx => ((DiaUnit)ctx).ACDGuid,
                                    extra => CombatTargeting.Instance.FirstNpc.Distance > 20f),
                                new CastOnUnit(SNOPower.Monk_TempestRush,
                                    ctx => ((DiaUnit)ctx).ACDGuid,
                                    extra => CombatTargeting.Instance.FirstNpc.Distance > 20f),

                                //Buffs
                                Mantra(),
                                Spell.Buff(SNOPower.Monk_MysticAlly, extra => !HasMysticAlly),
                                new SelfCast(SNOPower.Monk_SweepingWind, extra => !ZetaDia.Me.HasBuff(SNOPower.Monk_SweepingWind)),


                                //Focus Skills
                                new SelfCast(SNOPower.Monk_CycloneStrike,
                                    extra => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 20f) >= 4),
                                new SelfCast(SNOPower.Monk_SevenSidedStrike,
                                    extra => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 20f) >= 1),

                                //Secondary
                                new CastOnUnit(SNOPower.Monk_LashingTailKick,
                                    ctx => ((DiaUnit)ctx).ACDGuid,
                                    extra => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 20f) >= 4),
                                new SelfCast(SNOPower.Monk_BlindingFlash,
                                    ctx => Clusters.GetClusterCount(ZetaDia.Me, CombatTargeting.Instance.LastObjects, ClusterType.Radius, 20f) >= 5 ||
                                                (Common.IsElite((DiaUnit)ctx) && ((DiaUnit)ctx).Distance < 20f)),
                                new CastOnUnit(SNOPower.Monk_WaveOfLight,
                                    ctx => ((DiaUnit)ctx).ACDGuid),

                                new Decorator(ret => _explodingPalm.IsFinished && PowerManager.CanCast(SNOPower.Monk_ExplodingPalm),
                                    new Sequence(
                                        new CastOnUnit(SNOPower.Monk_ExplodingPalm, ctx => ((DiaUnit)ctx).ACDGuid),
                                        new Action(ret => _explodingPalm.Reset())
                                        )
                                ),

                                // Primary Skills. 
                                new CastOnUnit(SNOPower.Monk_DeadlyReach, ctx => ((DiaUnit)ctx).ACDGuid),
                                new CastOnUnit(SNOPower.Monk_CripplingWave, ctx => ((DiaUnit)ctx).ACDGuid),
                                new CastOnUnit(SNOPower.Monk_WayOfTheHundredFists, ctx => ((DiaUnit)ctx).ACDGuid),
                                new CastOnUnit(SNOPower.Monk_FistsofThunder, ctx => ((DiaUnit)ctx).ACDGuid)
                            )
                        ),

                   new Action(ret => RunStatus.Success)
                   );
        }

        private static Composite Mantra()
        {
            return new PrioritySelector(
                new SelfCast(SNOPower.Monk_MantraOfEvasion, extra => !ZetaDia.Me.HasBuff(SNOPower.Monk_MantraOfEvasion)),
                new SelfCast(SNOPower.Monk_MantraOfConviction, extra => !ZetaDia.Me.HasBuff(SNOPower.Monk_MantraOfConviction)),
                new SelfCast(SNOPower.Monk_MantraOfHealing, extra => !ZetaDia.Me.HasBuff(SNOPower.Monk_MantraOfHealing)),
                new SelfCast(SNOPower.Monk_MantraOfRetribution, extra => !ZetaDia.Me.HasBuff(SNOPower.Monk_MantraOfRetribution))
                );
        }

        #region timmers
        static Monk()
        {
            GameEvents.OnGameLeft += OnGameLeft;
            GameEvents.OnPlayerDied += OnGameLeft;
        }

        private static WaitTimer _explodingPalm = new WaitTimer(TimeSpan.FromSeconds(3));

        static void OnGameLeft(object sender, EventArgs e)
        {
            _explodingPalm.Stop();
        }
        #endregion

        public static bool HasMysticAlly
        {
            get
            {
                int dynId = ZetaDia.Me.CommonData.DynamicId;
                var summoned = ZetaDia.Actors.GetActorsOfType<DiaUnit>().FirstOrDefault(u => u.SummonedByACDId == dynId && u.Name.Contains("mysticAlly"));
                return summoned != null && summoned.CommonData != null;
            }
        }

        public static void MonkOnLevelUp(object sender, EventArgs e)
        {
            if (ZetaDia.Me.ActorClass != ActorClass.Monk)
                return;

            int myLevel = ZetaDia.Me.Level;

            Logger.Write("Player leveled up, congrats! Your level is now: {0}",
                myLevel
                );

            // Set Lashing tail kick once we reach level 2
            if (myLevel == 2)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.Monk_LashingTailKick, -1, 1);
                Logger.Write("Setting Lash Tail Kick as Secondary");
            }

            // Set Dead reach it's better then Fists of thunder imo.
            if (myLevel == 3)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.Monk_DeadlyReach, -1, 0);
                Logger.Write("Setting Deadly Reach as Primary");
            }

            // Make sure we set binding flash, useful spell in crowded situations!
            if (myLevel == 4)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.Monk_BlindingFlash, -1, 2);
                Logger.Write("Setting Binding Flash as Defensive");
            }

            // Binding flash is nice but being alive is even better!
            if (myLevel == 8)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.Monk_BreathOfHeaven, -1, 2);
                Logger.Write("Setting Breath of Heaven as Defensive");
            }

            // Make sure we set Dashing strike, very cool and useful spell great opener.
            if (myLevel == 9)
            {
                ZetaDia.Me.SetActiveSkill(SNOPower.Monk_DashingStrike, -1, 3);
                Logger.Write("Setting Dashing Strike as Techniques");
            }
        }
    }
}